package com.tom.springframework.beans.factory.support;

import cn.hutool.core.util.StrUtil;
import com.tom.springframework.beans.BeansException;
import com.tom.springframework.beans.factory.DisposableBean;
import com.tom.springframework.beans.factory.config.BeanDefinition;

import java.lang.reflect.Method;

/**
 * 销毁方法的适配器
 * <pre>
 *     使用适配器的原因：
 *      销毁的方法有两种或者更多中方式,目前有实现接口 {@code DisposableBean},
 *      还有通过注解配置 {@code #destroy-method} 两种方式,而这两种方式的销毁是
 *      由{@code AbstractApplicationContext} 向虚拟机注册钩子后、虚拟机关闭前执行。
 *
 * </pre>
 * <pre>
 *     在销毁的时候,更希望由同意的接口进行销毁,所以这里使用适配类,进行统一管理.
 * </pre>
 *
 * @author zx
 * @date 2024年11月24日 21:30
 */
public class DisposableBeanAdapter implements DisposableBean {

    private final Object bean;
    private final String beanName;
    private String destroyMethodName;

    public DisposableBeanAdapter(Object bean, String beanName, BeanDefinition beanDefinition) {
        this.bean = bean;
        this.beanName = beanName;
        this.destroyMethodName = beanDefinition.getDestroyMethodName();
    }

    @Override
    public void destroy() throws Exception {
        // 1. 实现接口 DisposableBean
        if (bean instanceof DisposableBean) {
            ((DisposableBean) bean).destroy();
        }

        // 2. 注解配置 destroy-method {判断是为了避免二次执行销毁}
        if (StrUtil.isNotEmpty(destroyMethodName) && !(bean instanceof DisposableBean && "destroy".equals(this.destroyMethodName))) {
            Method destroyMethod = bean.getClass().getMethod(destroyMethodName);
            if (null == destroyMethod) {
                throw new BeansException("Couldn't find a destroy method named '" + destroyMethodName + "' on bean with name '" + beanName + "'");
            }
            destroyMethod.invoke(bean);
        }
    }
}
